﻿// Write a method that calculates the number of workdays between today and given date, passed as parameter. 
// Consider that workdays are all days from Monday to Friday except a fixed list of public holidays specified preliminary as array.

namespace _05.WorkdaysBetweenTodayAndGivenDate
{
    using System;
    using System.Collections.Generic;
    using System.Globalization;

    public class WorkdaysBetweenTodayAndGivenDate
    {
        public static DateTime ConsoleInputDate(string format)
        {
            DateTime date;
            do
            {
                Console.Write("Enter date ({0}): ", format);
            }
            while (!DateTime.TryParseExact(Console.ReadLine(), format, CultureInfo.InvariantCulture, DateTimeStyles.None, out date));

            return date.Date;
        }

        public static int CountWorkdaysTo(DateTime endDate)
        {
            List<DayOfWeek> weekends = new List<DayOfWeek>
            {
                DayOfWeek.Saturday,
                DayOfWeek.Sunday
            };

            int workdays = 0;
            DateTime startDate = DateTime.Today;
            while (startDate < endDate)
            {
                if (!weekends.Contains(startDate.DayOfWeek) &&
                    !GetHolidays(startDate.Year).Contains(startDate))
                {
                    workdays++;
                }

                startDate = startDate.AddDays(1);
            }

            return workdays;
        }

        public static List<DateTime> GetHolidays(int currYear)
        {
            // constant Holidays
            List<DateTime> holidays = new List<DateTime>
            {
                new DateTime(currYear, 1, 1),
                new DateTime(currYear, 3, 3),
                new DateTime(currYear, 5, 1),
                new DateTime(currYear, 5, 6),
                new DateTime(currYear, 5, 24),
                new DateTime(currYear, 9, 22),
                new DateTime(currYear, 12, 24),
                new DateTime(currYear, 12, 25),
                new DateTime(currYear, 12, 26),
                new DateTime(currYear, 12, 31)
            };

            // Easter days
            DateTime easter = GetOrthodoxEaster(currYear);
            holidays.Add(easter.AddDays(-2));
            holidays.Add(easter.AddDays(-1));
            holidays.Add(easter);
            holidays.Add(easter.AddDays(1));

            return holidays;
        }

        public static DateTime GetOrthodoxEaster(int year)
        {
            int remain19 = year % 19;
            int remain7 = year % 7;
            int remain4 = year % 4;

            int remain30 = ((19 * remain19) + 16) % 30;
            int a = ((2 * remain4) + (4 * remain7) + (6 * remain30)) % 7;
            int b = ((19 * remain19) + 16) % 30;
            int key = b + a + 3;

            // Easterdate
            int month = 4;
            int day = key;
            if (key > 30)
            {
                month = 5;
                day = key - 30;
            }

            return new DateTime(year, month, day);
        }

        private static void Main()
        {
            DateTime endDate = ConsoleInputDate("dd/MM/yyyy");
            int workdays = CountWorkdaysTo(endDate);
            Console.WriteLine("Working days from Today({0}) to {1} are: {2}", DateTime.Today.ToShortDateString(), endDate.Date.ToShortDateString(), workdays);
        }
    }
}